package com.miku.blog.filter;

import com.miku.blog.domain.pojo.LoginUser;
import com.miku.blog.domain.pojo.SystemConstance;
import com.miku.blog.eume.HttpStatusEnum;
import com.miku.blog.utils.GenerateKeyUtils;
import com.miku.blog.utils.RedisCache;
import com.miku.blog.utils.WebUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 *
 * 身份认证过滤器
 * @author shkstart
 * @create ${}YEAR-06-03 14:41
 */
public class AuthenticationTokenFilter extends OncePerRequestFilter {

    private RedisCache redisCache;

    private PasswordEncoder passwordEncoder;

    public AuthenticationTokenFilter() {
    }

    public AuthenticationTokenFilter(RedisCache redisCache, PasswordEncoder passwordEncoder) {
        this.redisCache = redisCache;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {


        Integer isAnonymous = (Integer) request.getAttribute(SystemConstance.REQUEST_ATTRIBUTE_RESOURCE_ANONYMOUS);
        if (SystemConstance.IS_ANONYMOUS.equals(isAnonymous)) {
            setContext(request,null,null);
            filterChain.doFilter(request, response);
            return;
        }


//        if (Objects.isNull(request.getSession(false))) {
//            WebUtils.sendResponseResult(response, HttpStatusEnum.PLEASE_LOGIN_FIRST);
//            return;
//        }

        String redisCacheKey
                = GenerateKeyUtils.generateRedisCacheKey(request, null);

        LoginUser loginUser = redisCache.getCacheObject(redisCacheKey);
        if (Objects.isNull(loginUser)) {
            WebUtils.sendResponseResult(response, HttpStatusEnum.NEED_LOGIN_AGAIN);
            return;
        }
        if (!loginUser.isEnabled()) {
            WebUtils.sendResponseResult(response, HttpStatusEnum.USER_IS_DISABLE);
            return;
        }


        String token = request.getHeader(SystemConstance.REQUEST_HEADER_TOKEN_KEY);
        String tokenKey = null;
        if (StringUtils.hasText(token)) {
            token = GenerateKeyUtils.generatePasswordEncodeKey(token);
            tokenKey = GenerateKeyUtils.generateTokenKey(loginUser);
        }
        if (!StringUtils.hasText(tokenKey) || !passwordEncoder.matches(tokenKey, token)) {
            WebUtils.sendResponseResult(response, HttpStatusEnum.TOKEN_UNLAWFUL);
            return;
        }

        setContext(null,loginUser,redisCacheKey);

        filterChain.doFilter(request, response);
    }





    private void setContext(HttpServletRequest request,
                            LoginUser loginUser,
                            String redisCacheKey) {


        if (Objects.nonNull(request)) {
//            HttpSession session = request.getSession(false);
//            if (Objects.isNull(session) || !StringUtils.hasText(token)) {
//                return;
//            }
            String token = request.getHeader(SystemConstance.REQUEST_HEADER_TOKEN_KEY);
            if (!StringUtils.hasText(token)) {
                return;
            }

            redisCacheKey = GenerateKeyUtils.generateRedisCacheKey(request, null);
            loginUser = redisCache.getCacheObject(redisCacheKey);
            if (Objects.isNull(loginUser)) {
                return;
            }
            String key = GenerateKeyUtils.generateTokenKey(loginUser);
            String encodeKey = GenerateKeyUtils.generatePasswordEncodeKey(token);
            if (!passwordEncoder.matches(key, encodeKey)) {
                return;
            }
        }

//        Long expireTime = redisCache.getCacheObjectExpireTime(redisCacheKey);
//        if (expireTime < SystemConstance.REDIS_KEY_TIME_REMAINING && expireTime > 0) {
            redisCache.setCacheObjectExpireTime(redisCacheKey,
                    SystemConstance.REDIS_EXPIRE_TIME,
                    SystemConstance.REDIS_TIMEUNIT);
            redisCache.setCacheObjectExpireTime(GenerateKeyUtils.getRedisUserCacheKey(loginUser.getUserAuth().getId())
                    , SystemConstance.REDIS_ID_KEY_EXPIRE_TIME,
                    SystemConstance.REDIS_TIMEUNIT);
//        }

        UsernamePasswordAuthenticationToken authentication
                = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

}
